package common.server.redis;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.PostConstruct;

import common.server.redis.config.RedisProperties;
import common.server.redis.jedis.DefaultJedisSentinelClient;
import common.server.redis.jedis.pool.JedisSentinelReadOrWritePool;
import common.server.redis.redisson.DefaultRedissonClient;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;

import redis.clients.jedis.JedisPoolConfig;

/**
 * redis 客户端服务 提供给运营平台使用
 * 
 * @author Administrator
 * @version [版本号, 2017/11/24 0024]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class RedisClientFactory {

	/**
	 * 配置信息
	 */
	private RedisProperties redisProperties;

	/**
	 * 客户端资源
	 */
	private RedisClient client;

	/**
	 * 初始化类
	 */
	@PostConstruct
	private void init() {
		if (this.client == null) {
			synchronized (this.client) {
				if (null == redisProperties
						|| redisProperties.getPool() == null) {
					throw new RuntimeException("redis Properties is null");
				}
				String mode = redisProperties.getMode();
				switch (mode) {
				case "single":
					this.client = buildSingleClient();
					break;
				case "cluster":
					this.client = buildClusterClient();
					break;
				case "sentinel":
					this.client = buildSentinelClient();
					break;
				default:
					throw new RuntimeException(
							"redis Properties [mode] is null");
				}

			}
		}
	}

	/**
	 *
	 * @return
	 */
	public RedisClient getClient() {
		return this.client;
	}

	/**
	 * 构建集群客户端
	 * 
	 * @return
	 */
	private RedisClient buildClusterClient() {
		if (null == redisProperties.getCluster()) {
			throw new RuntimeException("Cluster Properties is null");
		}
		Config config = new Config();
		String[] nodes = redisProperties.getCluster().getNodes().split(",");
		List<String> newNodes = new ArrayList(nodes.length);
		Arrays.stream(nodes).forEach((index) -> newNodes.add(
				index.startsWith("redis://") ? index : "redis://" + index));
		ClusterServersConfig serverConfig = config.useClusterServers()
				.addNodeAddress(newNodes.toArray(new String[0]))
				.setScanInterval(redisProperties.getCluster().getScanInterval())
				.setIdleConnectionTimeout(
						redisProperties.getPool().getSoTimeout())
				.setConnectTimeout(redisProperties.getPool().getConnTimeout())
				.setFailedAttempts(
						redisProperties.getCluster().getFailedAttempts())
				.setRetryAttempts(
						redisProperties.getCluster().getRetryAttempts())
				.setRetryInterval(
						redisProperties.getCluster().getRetryInterval())
				.setMasterConnectionPoolSize(redisProperties.getCluster()
						.getMasterConnectionPoolSize())
				.setSlaveConnectionPoolSize(redisProperties.getCluster()
						.getSlaveConnectionPoolSize())
				.setTimeout(redisProperties.getTimeout());
		if (StringUtils.isNotBlank(redisProperties.getPassword())) {
			serverConfig.setPassword(redisProperties.getPassword());
		}
		System.out.println("ClusterServersConfig:" + serverConfig);
		return new DefaultRedissonClient(Redisson.create(config));
	}

	/**
	 * 构建单机客户端
	 * 
	 * @return
	 */
	private RedisClient buildSingleClient() {
		if (null == redisProperties.getSingle()) {
			throw new RuntimeException("Single Properties is null");
		}
		Config config = new Config();
		String node = redisProperties.getSingle().getAddress();
		node = node.startsWith("redis://") ? node : "redis://" + node;
		SingleServerConfig serverConfig = config.useSingleServer()
				.setAddress(node)
				.setTimeout(redisProperties.getPool().getConnTimeout())
				.setConnectionPoolSize(redisProperties.getPool().getSize())
				.setConnectionMinimumIdleSize(
						redisProperties.getPool().getMinIdle());
		if (StringUtils.isNotBlank(redisProperties.getPassword())) {
			serverConfig.setPassword(redisProperties.getPassword());
		}

		return new DefaultRedissonClient(Redisson.create(config));
	}

	/**
	 * 构建哨兵客户端
	 * 
	 * @return
	 */
	private RedisClient buildSentinelClient() {
		if (null == redisProperties.getSentinel()) {
			throw new RuntimeException("Sentinel Properties is null");
		}
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxIdle(redisProperties.getPool().getMaxIdle());
		config.setMaxWaitMillis(redisProperties.getPool().getMaxWait());
		config.setMinIdle(redisProperties.getPool().getMinIdle());
		config.setTestOnBorrow(true);
		config.setTestWhileIdle(true);
		config.setTestOnReturn(true);
		JedisSentinelReadOrWritePool pool = new JedisSentinelReadOrWritePool(
				redisProperties.getSentinel().getMaster(),
				redisProperties.getSentinel().getNodes(), config,
				redisProperties.getPassword(),
				redisProperties.getPool().getConnTimeout(),
				redisProperties.getPool().getSoTimeout(),
				redisProperties.getSentinel().getFailMax(),
				redisProperties.getSentinel().isMasterOnlyWrite(), "");
		return new DefaultJedisSentinelClient(pool);
	}

	public RedisProperties getRedisProperties() {
		return redisProperties;
	}

	public void setRedisProperties(RedisProperties redisProperties) {
		this.redisProperties = redisProperties;
	}
}
